package plgnet

/*
  是一个数据生产者
*/

import (
	"dgo/MyProj/PrjConf"
	"dgo/MyProj/PrjHttpUtils"
	"dgo/goutils/dnet"
	"dgo/goutils/utils"
	"fmt"
	"gitee.com/ymofen/gobase/golog"
	"gitee.com/ymofen/supervalue"
	"time"
)

type PlgNetTcpClt struct {
	PlgBase
	tcpclt     *dnet.TcpClt
	send_queue int8
	debugmode  int8

	last_dis       string
	nmea           string
	nmea_task_flag int32
	releaseflag    int
	conn_n         int

	afterconnected_sendstr string

	outputEx *PlgBaseInnerEx
}

func NewProjTcpClientPlug() *PlgNetTcpClt {
	rval := &PlgNetTcpClt{}
	return rval
}

/*
**

	响应HttpStatus请求
*/
func (this *PlgNetTcpClt) OnHttpStatus(rec *PlgHttpRec) (rval interface{}, errcode int, err error) {
	itype := rec.QryAsInt("type", 0)
	if itype == 99 {
		json := wrapper.NewSVObject()
		json.SetKeyValues("plugid", this.PlugId, "uuid", PrjConf.APP_UUID,
			"remote-addr", this.tcpclt.GetRemoteAddr(),
			"recv-monitor", this.tcpclt.RecvMonitor.Info(),
			"send-monitor", this.tcpclt.SendMonitor.Info(),
			"send-queue", this.send_queue,
			"send-afterconnected-str", this.afterconnected_sendstr,
			"conn-n", this.conn_n,
			"debug-mode", this.debugmode,
			"lastdis", this.last_dis)
		if rec.QryAsInt("json", 0) == 1 {
			PrjHttpUtils.ResponseAsJSON(rec.RespW, json.AsJSONStringEx(false, true))
		} else {
			PrjHttpUtils.JSON2TableRec(rec.RespW, "", json.AsJSONString(false))
		}
	} else if itype == 98 {
		//rec.ResponseSyncListNEx(this.msglst)
	} else if itype == 1 {
		json := wrapper.NewSVArray()
		//searchval := rec.QryAsString("searchval", "")
		//
		//this.lstDevice.ListRangeV2(func(key, value interface{}) bool {
		//	//dev := value.(*YsledMqttWebServDevice)
		//	ok := true
		//	if len(searchval) > 0 {
		//
		//	}
		//	return ok
		//}, func(k0, v0, k1, v1 interface{}) bool {
		//	return true
		//}, func(key, val interface{}) bool {
		//	return true
		//})

		if rec.QryAsInt("json", 0) == 1 {
			PrjHttpUtils.ResponseAsJSON(rec.RespW, json.AsJSONStringEx(false, false))
		} else {
			PrjHttpUtils.JSON2Table(rec.RespW, "", json.AsJSONString(false))
		}
	} else {
		var sb utils.BytesBuilder
		PrjHttpUtils.AppendIndexBody(&sb, "status", "status?type=99")
		PrjHttpUtils.AppendIndexBody(&sb, "msglist", "status?type=98&n=100&searchval=")
		PrjHttpUtils.ResponseBodyHtml(rec.RespW, sb.String())
	}
	return

	return
}

/*
*

	  {
	    "id":"tcpclt",
	    "type":"net.tcpclt.raw",
	    "conf":{
			"input":{        // 如果指定了input则将订阅到的数据通过tcpclt进行发送
			   "id":"",
			   "topic":"topic"
			 },
	        "send-queue":1,
	        "debug-mode":1,
			"remoteaddr":"127.0.0.1:2101",
	        "afterconnected":{
	            "str":"",
	         },
			"output":{

			}
	    }
	  }
*/
func (this *PlgNetTcpClt) ReloadConf(conf *wrapper.SuperValue) (err error) {
	if this.outputEx == nil {
		this.outputEx = PlgNewInnerEx()
	}
	if this.tcpclt == nil {
		this.tcpclt = dnet.NewTcpClt("")
		this.tcpclt.AfterRecvBuf = this.OnRecvNtripCltBuffer
		this.tcpclt.RecvMonitor = utils.NewMonitorSpeedSizeRec()
		this.tcpclt.SendMonitor = utils.NewMonitorSpeedSizeRec()
		utils.Monitor.AddMonitor(this.tcpclt.RecvMonitor)
		utils.Monitor.AddMonitor(this.tcpclt.SendMonitor)
		this.tcpclt.AfterDisconnected = func(sender *dnet.TcpClt) {
			this.last_dis = fmt.Sprintf("[%s]%s", utils.NowString(), sender.DisReason)
			if this.debugmode == 1 {
				golog.Infof("断线:%s", sender.DisReason)
			}
		}
		this.tcpclt.ConnectedFail = func(sender *dnet.TcpClt, err error) {
			this.last_dis = fmt.Sprintf("[%s]连接失败:%s", utils.NowString(), err.Error())
			if this.debugmode == 1 {
				golog.Infof("连接失败:%s", err.Error())
			}
		}
		this.tcpclt.AfterConnected = func(sender *dnet.TcpClt) {
			this.conn_n++
			if this.debugmode == 1 {
				golog.Infof("连接服务器成功!")
			}
			time.AfterFunc(time.Second, func() {
				if len(this.afterconnected_sendstr) > 0 {
					this.innerDispBuf([]byte(this.afterconnected_sendstr))
				}
			})
		}
	}
	this.debugmode = int8(conf.IntByName("debug-mode", 0))
	this.send_queue = int8(conf.IntByName("send-queue", 0))
	this.afterconnected_sendstr = conf.StringByPath("afterconnected.str", "")
	changed := false
	conf.CheckStrFunc("remoteaddr", func(strv string) {
		strv = utils.ReplacePlaceholder(strv, "$$", "$$")
		if this.tcpclt.SetAddress(strv) {
			changed = true
		}
	})

	if changed {
		if !this.tcpclt.Active() {
			this.tcpclt.Start()
		} else {
			this.tcpclt.RequestDisconnect("配置改变")
		}
	} else {
		err = utils.EUnChangedErr
	}

	this.outputEx.ReloadConf(conf.ValueByName("output"))

	this.ReloadInputConf(conf.ValueByName("input"), this.OnInputSubscribeCallback)

	return
}

func (this *PlgNetTcpClt) innerDispBuf(buf []byte) error {
	if this.send_queue == 1 {
		utils.DefaultWorkers().PostTaskFunc(this, func() {
			_, err := this.tcpclt.Write(buf)
			if err != nil {
				if this.debugmode == 1 {
					golog.Infof("发送数据异常[%d]:%s, err:%s", len(buf), utils.BufToHexStr(buf, 100, ""), err.Error())
				}
			} else {
				if this.debugmode == 1 {
					golog.Infof("发送数据成功[%d]:%s", len(buf), utils.BufToHexStr(buf, 100, ""))
				}
			}
		})
		return nil
	}
	_, err := this.tcpclt.Write(buf)
	if err != nil {
		if this.debugmode == 1 {
			golog.Infof("发送数据异常[%d]:%s, err:%s", len(buf), utils.BufToHexStr(buf, 100, ""), err.Error())
		}
		return err
	} else {
		if this.debugmode == 1 {
			golog.Infof("发送数据成功[%d]:%s", len(buf), utils.BufToHexStr(buf, 100, ""))
		}
	}
	return nil
}

func (this *PlgNetTcpClt) SendKVs(topic string, kv ...interface{}) error {
	if this.tcpclt != nil {
		l := len(kv)
		if l == 1 {
			if buf, ok := kv[0].([]byte); ok {
				this.innerDispBuf(buf)
				return nil
			}
		}

		json := wrapper.NewSVObject()
		json.SetKeyValues(kv...)
		buf := json.AsJSONBytesEx(false, true)
		this.innerDispBuf(buf)
		return nil
	} else {
		return fmt.Errorf("WS连接尚未进行创建")
	}
}

func (this *PlgNetTcpClt) DispatchData(channelid string, sender interface{}, data interface{}, tag interface{}) (err error) {
	err = this.SendKVs(channelid, data)
	return err
}

func (this *PlgNetTcpClt) OnRecvNtripCltBuffer(sender *dnet.TcpClt, buffer []byte) {
	this.outputEx.OutputTaskBuffer(buffer)
}

func (this *PlgNetTcpClt) OnInputSubscribeCallback(sender interface{}, channelid string, subscribeid interface{}, data interface{}, tag interface{}, isBreak *bool) bool {
	tcpclt := this.tcpclt
	if tcpclt != nil {
		if buf, ok := data.([]byte); ok {
			tcpclt.Write(buf)
		}
	}
	return true
}

func (this *PlgNetTcpClt) OnObjectNotify(sender interface{}, notifytype int, data interface{}) (rval interface{}, err error) {
	if notifytype == utils.NOTIFY_TYPE_SETCONF {
		if conf, ok := data.(*wrapper.SuperValue); ok {
			err = this.ReloadConf(conf)
		} else {
			err = fmt.Errorf("非法的JSON配置")
		}
	} else if notifytype == utils.NOTIFY_TYPE_RELEASE {
		this.releaseflag = 1
		this.outputEx.Release()
		if this.tcpclt != nil {
			utils.Monitor.RemoveMonitorRec(this.tcpclt.RecvMonitor)
			utils.Monitor.RemoveMonitorRec(this.tcpclt.SendMonitor)
		}
	}
	return
}

func CreateTcpClientPlugFunc(args ...interface{}) (rval interface{}, err error) {
	obj := NewProjTcpClientPlug()
	if len(args) > 0 {
		if str, ok := args[0].(string); ok {
			obj.PlugId = str
		}
	}
	rval = obj
	return
}
